<script setup lang="ts">
import type { TabPaneName, TreeInstance } from 'element-plus'
import type { CodeMateField, CodeMateMethod, CodeMateModel, CodeMateModule, CodeMateProject, CodeMateTreeNode } from '@/apis/code/codeMateApi'
import { Back, Plus } from '@element-plus/icons-vue'
import { onMounted, provide, ref, watch } from 'vue'
import { codeMateProjectApi } from '@/apis/code/codeMateApi'
import BaseCard from '@/layouts/BaseCard.vue'
import CodeFieldForm from './components/CodeFieldForm.vue'
import CodeMateTypeTag from './components/CodeMateTypeTag.vue'
import CodeMethodForm from './components/CodeMethodForm.vue'
import CodeModelForm from './components/CodeModelForm.vue'
import CodeModuleForm from './components/CodeModuleForm.vue'
import CodeProjectForm from './components/CodeProjectForm.vue'

const { projectName } = defineProps<{
  projectName?: string
}> ()

const project = ref<CodeMateProject>()

const treeData = ref<CodeMateTreeNode[]>([])
const models = ref <CodeMateModel[]>([])

onMounted(async () => {
  if (projectName === '' || projectName === undefined) {
    openFormTab({
      type: 'project',
      data: { } as CodeMateProject,
    })
  }
  else {
    await loadData(projectName)
    clickTreeNode(treeData.value[0].id)
  }
})

watch(() => projectName, async () => {
  if (projectName !== '' && projectName !== undefined) {
    await loadData(projectName)
    clickTreeNode(treeData.value[0].id)
  }
})

async function loadData(projectName: string) {
  project.value = await codeMateProjectApi.findDetail(projectName)
  models.value = []
  const moduleList: CodeMateTreeNode[] = []
  for (const module of project.value.moduleList) {
    const modelList: CodeMateTreeNode[] = []
    for (const model of module.modelList) {
      models.value.push(model)
      const methodList: CodeMateTreeNode[] = []
      for (const method of model.methodList) {
        methodList.push({ id: method.id, label: method.name, remark: method.remark, type: 'method', data: method })
      }
      modelList.push({ id: model.id, label: model.name, remark: model.remark, type: 'model', data: model, children: [...methodList] })
    }
    moduleList.push({ id: module.id, label: module.moduleName, remark: module.remark, type: 'module', data: module, children: modelList })
  }
  treeData.value = [{ id: project.value.id, label: project.value.projectName, remark: project.value.remark, type: 'project', data: project.value, children: moduleList }]
}

const selectId = ref<number>()
const selectIndex = ref<number>()
const tabNodes = ref<Partial<CodeMateTreeNode>[]>([])

function openFormTab(node: Partial<CodeMateTreeNode>) {
  selectId.value = node.id
  selectIndex.value = undefined
  if (node.id !== undefined) {
    for (let i = 0; i < tabNodes.value.length; i++) {
      if (tabNodes.value[i].id === node.id) {
        tabNodes.value[i] = node
        selectIndex.value = i
        break
      }
    }
  }
  if (selectIndex.value === undefined) {
    tabNodes.value.push(node)
    selectIndex.value = tabNodes.value.length - 1
  }
}

const treeRef = ref<TreeInstance>()
function clickTreeNode(id: number) {
  treeRef.value?.setCurrentKey(`${id}`)
  const node = treeRef.value?.getNode(`${id}`)
  if (node) {
    openFormTab(node.data as CodeMateTreeNode)
  }
  else {
    selectIndex.value = undefined
  }
}

provide('loadProjectData', () => projectName && loadData(projectName))
provide('clickTreeNode', clickTreeNode)
provide('models', models)

function onTabRemove(paneName: TabPaneName) {
  const index = paneName as number
  if (selectIndex.value && index <= selectIndex.value) {
    selectIndex.value = index === selectIndex.value ? index - 1 : index
  }
  tabNodes.value.splice(index, 1)
}
</script>

<template>
  <div class="h-full flex flex-row gap-2 overflow-hidden">
    <BaseCard class="w-80">
      <template #title>
        <div class="flex flex-row items-center justify-center gap-2">
          <el-icon @click="$router.replace('/code/mate/project')">
            <Back />
          </el-icon>
          <div>列表</div>
        </div>
      </template>
      <template v-if="project" #buttons>
        <el-button
          type="primary" :icon="Plus" @click="openFormTab({
            type: 'module',
            data: {
              parentId: project.id,
              moduleName: project.moduleName,
              moduleCode: project.moduleCode,
            } as CodeMateModule })"
        >
          添加
        </el-button>
      </template>
      <el-tree
        ref="treeRef"
        :data="treeData"
        node-key="id"
        default-expand-all
        :expand-on-click-node="false"
        :props="{ class: (data) => data.id === selectId ? 'tree-selected' : '' }" @node-click="(node) => openFormTab(node)"
      >
        <template #default="{ node, data }">
          <div class="w-full flex flex-row justify-between">
            <div>
              <span class="mate-tree-remark">{{ data.remark }}</span>
              <span class="mate-tree-label">{{ node.label }}</span>
            </div>
            <CodeMateTypeTag :data="data" class="mate-tree-tip" />
          </div>
        </template>
      </el-tree>
    </BaseCard>

    <BaseCard class="flex-1 overflow-auto">
      <el-tabs
        v-model="selectIndex"
        closable
        @tab-remove="onTabRemove"
      >
        <el-tab-pane
          v-for="(node, index) in tabNodes" :key="index"
          :name="index"
        >
          <template #label>
            {{ node.data?.remark }} <CodeMateTypeTag :data="node as CodeMateTreeNode" class="mate-tree-tip" />
          </template>
          <CodeProjectForm v-if="node.type === 'project' " :data="node.data as CodeMateProject" @remove="onTabRemove(index)" />
          <CodeModuleForm v-if="node.type === 'module'" :data="node.data as CodeMateModule" @remove="onTabRemove(index)" />
          <CodeModelForm v-if="node.type === 'model' " :data="node.data as CodeMateModel" @remove="onTabRemove(index)" />
          <CodeFieldForm v-if="node.type === 'field' " :data="node.data as CodeMateField" @remove="onTabRemove(index)" />
          <CodeMethodForm v-if="node.type === 'method' " :data="node.data as CodeMateMethod" @remove="onTabRemove(index)" />
        </el-tab-pane>
      </el-tabs>
    </BaseCard>
  </div>
</template>

<style lang="css" scoped>
.mate-tree-label {
  --at-apply: ml-2 text-xs text-secondary italic;
}

.mate-tree-tip {
  --at-apply: text-xs px-1;
}

:deep(.tree-selected > .el-tree-node__content) {
  --at-apply: bg-active text-active;
}

:deep(.tree-selected.el-tree-node:focus > .el-tree-node__content) {
  --at-apply: bg-active;
}
</style>
